package hm.base.dao.impl;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.util.Assert;

import com.trendytech.tds.common.bean.Pager;
import com.trendytech.tds.common.util.PagerUtils;

import hm.base.dao.IBaseDAO;
import hm.base.dao.IDGenerator;
import hm.entity.AbstractEntity;
import hm.entity.IUUIDEntity;

public abstract class AbstractDAO<T> implements IBaseDAO<T> {
	
	protected static final IDGenerator ID_GENERATOR = new IDGenerator();
	
	/**
	 * 默认的插入记录的SQL映射ID
	 */
	public static final String MAPPER_INSERT = "insert";
	
	/**
	 * 默认的更新记录的SQL映射ID
	 */
	public static final String MAPPER_UPDATE_BY_ID = "update";
	
	/**
	 * 默认的根据ID查询记录的SQL映射ID
	 */
	public static final String MAPPER_SELECT_BY_ID = "selectById";
	
	/**
	 * 默认的根据ID删除记录的SQL映射ID
	 */
	public static final String MAPPER_DELETE_BY_ID = "delete";
	/**
	 * 逻辑删除记录
	 */
	public static final String MAPPER_DELETE_LOGICAL = "deleteLogical";
	
	/**
	 * 默认的查询记录列表的SQL映射ID
	 */
	public static final String MAPPER_SELECT_LIST = "selectList";
	
	/**
	 * 条件查询的SQL映射ID
	 */
	public static final String MAPPER_SELECT_BY_PARAM = "selectByParam";
	
	protected Log logger = LogFactory.getLog(getClass());
	
	/**
	 * 实体对象的类
	 */
	private Class<T> entityClass;
	
	/**
	 * SQL的命名空间
	 */
	protected String nameSpace;
	
	@Autowired
	protected SqlSession sqlSession;
	@Autowired
	protected DataSource dataSource;
	
	private SQLErrorCodeSQLExceptionTranslator sqlExceptionTranslator;

	@SuppressWarnings("unchecked")
	public AbstractDAO() {
		@SuppressWarnings("rawtypes")
		Class c = getClass();
		Type type = c.getGenericSuperclass();
		if (type instanceof ParameterizedType) {
			Type[] parameterizedType = ((ParameterizedType) type)
					.getActualTypeArguments();
			this.entityClass = (Class<T>) parameterizedType[0];
			nameSpace = entityClass.getCanonicalName();
		}
	}

	@Override
	public String generateId() {
		return ID_GENERATOR.generate();
	}
	/**
	 * 插入记录前的动作，内部方法。
	 * @param entity
	 */
	private void beforeInsertInternal(T entity) {
		if (entity instanceof IUUIDEntity) {//id生成
			IUUIDEntity model = (IUUIDEntity) entity;
			if (StringUtils.isEmpty(model.getId())) {
				model.setId(ID_GENERATOR.generate());
			}
		}
		if (entity instanceof AbstractEntity) {
			AbstractEntity model = (AbstractEntity) entity;
			if (model.getCreateTime() == null) {
				model.setCreateTime(new Date());
			}
		}
	}
	/**
	 * 更新记录前的动作，内部方法。
	 * @param entity
	 */
	private void beforeUpdateInternal(T entity) {
		if (entity instanceof AbstractEntity) {
			AbstractEntity model = (AbstractEntity) entity;
/*			if (model.getModifyTime() == null) {
				model.setModifyTime(new Date());
			}*/
		}
	}

	/**
	 * 插入记录前的动作，子类可覆盖以实现自己的逻辑。
	 * @param entity
	 */
	protected void beforeInsert(T entity) {
	}

	protected void beforeUpdate(T entity) {
	}
	protected String getMapperId(String mapperId) {
		return nameSpace + "." + mapperId;
	}

	/**
	 * 分版本获取MapperId，版本+下划线+mapperId
	 * @param mapperId
	 * @param versionName
	 * @return
	 */
	protected String getMapperId(String mapperId, String versionName) {
		if(versionName != null){
			return nameSpace + "." + versionName + "_" + mapperId;
		}
		return nameSpace + "." + mapperId;
	}
	
	@Override
	public int insert(T entity) {
		Assert.notNull(entity, "entity is required");
		beforeInsertInternal(entity);
		// 调用插入前逻辑
		beforeInsert(entity);
//		System.out.println(entity);
		return sqlSession.insert(getMapperId(MAPPER_INSERT), entity);
	}

	@Override
	public int update(T entity) {
		Assert.notNull(entity, "entity is required");
		beforeUpdateInternal(entity);
		// 调用插入前逻辑
		beforeUpdate(entity);
		return sqlSession.update(getMapperId(MAPPER_UPDATE_BY_ID), entity);
	}

	@Override
	public int delete(String id) {
		Assert.notNull(id, "id is required");
		return sqlSession.delete(getMapperId(MAPPER_DELETE_BY_ID), id);
	}
	@Override
	public int deleteLogical(T entity) {
		Assert.notNull(entity, "entity is required");
		if (entity instanceof AbstractEntity) {
			AbstractEntity model = (AbstractEntity) entity;
/*			if (model.getDeleteTime() == null) {
				model.setDeleteTime(new Date());
			}*/
		}
		return sqlSession.update(getMapperId(MAPPER_DELETE_LOGICAL), entity);
	};

	@SuppressWarnings("unchecked")
	@Override
	public T getById(String id) {
		Assert.notNull(id, "id is required");
		return (T)sqlSession.selectOne(getMapperId(MAPPER_SELECT_BY_ID), id);
	}

	@Override
	public List<T> getList(String sqlId, Object params) {
		Assert.notNull(sqlId, "sqlId is required");
		return sqlSession.selectList(getMapperId(sqlId), params);
	}
	
	/**
	 * 不使用泛型
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public List getListBySql(String sqlId, Object params) {
		Assert.notNull(sqlId, "sqlId is required");
		return sqlSession.selectList(getMapperId(sqlId), params);
	}
	
	@Override
	public List<T> getByPager(Pager<T> pager) {
//		Integer pageNumber = pager.getPageNumber();
		List<T> list = null;
		try {
			Integer pageSize = pager.getPageSize();
			RowBounds rowBounds = new RowBounds(PagerUtils.getStart(pager),
					pageSize);
			list = sqlSession.selectList(getMapperId(MAPPER_SELECT_LIST),
					pager, rowBounds);
			pager.setList(list);
		} catch (Exception e) {
			logger.error("", e);
		}
		return list;
	}

	/**
	 * 使用指定SQL的分页方法
	 * 
	 * @param sqlId
	 * @param pager
	 * @return
	 */
	protected Pager<T> getByPager(String sqlId, Pager<T> pager) {
		Assert.notNull(sqlId, "sqlId is required");
		Assert.notNull(pager, "pager is required");
		Integer pageSize = pager.getPageSize();
		RowBounds rowBounds = new RowBounds(PagerUtils.getStart(pager),
				pageSize);
		List<T> list = sqlSession.selectList(getMapperId(sqlId), pager,
				rowBounds);
		pager.setList(list);
		return pager;
	}

	/**
	 * 不使用泛型的分页查询
	 * 
	 * @param sqlId
	 * @param pager
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected Pager getPagerBySql(String sqlId, Pager pager) {
		Assert.notNull(sqlId, "sqlId is required");
		Assert.notNull(pager, "pager is required");
		Integer pageSize = pager.getPageSize();
		RowBounds rowBounds = new RowBounds(PagerUtils.getStart(pager),
				pageSize);
		List list = sqlSession.selectList(getMapperId(sqlId), pager, rowBounds);
		pager.setList(list);
		return pager;
	}
	
	protected SQLExceptionTranslator getSqlExceptionTranslator(){
		if(sqlExceptionTranslator == null){
			sqlExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);
		}
		return sqlExceptionTranslator;
	}
	
}
